package main

import "fmt"
import "strconv"

// ==========基本数据类型转换==========
// 1、Go在不同类型的变量之间赋值时需要显示转换
// 2、Go中数字类型的变量转换可以从表示范围小转换到表示范围大的, 也可以从表示范围大转换到表示范围小的
// 3、数字类型变量从表示范围大转换到表示范围小的, 编译器不会报错, 按溢出处理
// 4、两种不同数字类型的变量做逻辑运算, 除了要转换成相同类型的, 还要保证不超过类型所能表示的范围

// 基本数据类型转基本数据类型
func BaseToBase() {
	// 范围小 --> 范围大、范围大 --> 范围小
	var i int8 = 100
	var f float32 = float32(i)
	var u uint8 = uint8(f)
	fmt.Println(f, u)

	var m = 1000
	var n = int8(m)
	fmt.Println(m, n) // 1000 -24
}

// 基本数据类型转换成字符串
func BaseToStringSprintf() {
	var num1 = 99
	var num2 = 1.2
	var b bool
	var ch = 'A'
	var str string

	// 整数转字符串
	str = fmt.Sprintf("%d", num1)
	fmt.Println(str)

	// 浮点数转字符串
	str = fmt.Sprintf("%f", num2)
	fmt.Println(str)

	// 布尔型转字符串
	str = fmt.Sprintf("%t", b)
	fmt.Println(str)

	// 字符转字符串
	str = fmt.Sprintf("%c", ch)
	fmt.Println(str)
}

// 基本数据类型转换成字符串
func BaseToStringStrconv() {
	var num1 = 99
	var num2 = 3.1415926535897936264
	var num3 = 3.1415926535897936264 + 3.1415926535897936264i
	var b bool
	var str string

	// 整数类型转字符串类型
	// • FormatInt(i int64, base int) string
	// 参数说明:
	// - base: 将int64类型的整数i转换为对应base进制类型的字符串, 2 <= base <= 36, 否则panic
	str = strconv.FormatInt(int64(num1), 2)  // 1100011
	str = strconv.FormatInt(int64(num1), 8)  // 143
	str = strconv.FormatInt(int64(num1), 10) // 99
	str = strconv.FormatInt(int64(num1), 16) // 63
	// • Itoa(i int) string
	// Itoa is equivalent to FormatInt(int64(i), 10)
	str = strconv.Itoa(num1) // 99

	// 无符号整型转字符串类型
	// • FormatUint(i uint64, base int) string
	// 参数说明:
	// - base: 将uint64类型的整数i转换为对应base进制类型的字符串, 2 <= base <= 36, 否则panic
	str = strconv.FormatUint(uint64(num1), 2)  // 1100011
	str = strconv.FormatUint(uint64(num1), 8)  // 143
	str = strconv.FormatUint(uint64(num1), 10) // 99
	str = strconv.FormatUint(uint64(num1), 16) // 63

	// 浮点数类型转字符串类型
	// • FormatFloat(f float64, fmt byte, prec, bitSize int) string
	// 参数说明:
	// - fmt: 输出字符串的格式
	// 'b' (-ddddp±ddd, a binary exponent),
	// 'e' (-d.dddde±dd, a decimal exponent),
	// 'E' (-d.ddddE±dd, a decimal exponent),
	// 'f' (-ddd.dddd, no exponent),
	// 'g' ('e' for large exponents, 'f' otherwise),
	// 'G' ('E' for large exponents, 'f' otherwise),
	// 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent),
	// 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent).
	// - prec: 小数点后保留几位小数
	// - bitSize: 32或64, 否则panic, 若转换为32位的, 则可能精度损失
	str = strconv.FormatFloat(num2, 'f', 10, 32) // 3.1415927410
	str = strconv.FormatFloat(num2, 'f', 10, 64) // 3.1415926536
	str = strconv.FormatFloat(num2, 'e', 10, 64) // 3.1415926536e+00
	str = strconv.FormatFloat(num2, 'E', 10, 64) // 3.1415926536E+00

	// 布尔类型转字符串类型
	// • FormatBool(b bool) string
	str = strconv.FormatBool(b)

	// 复数类型转字符串类型
	// • FormatComplex(c complex128, fmt byte, prec, bitSize int) string
	// 参数说明:
	// - fmt: same meaning as in FormatFloat
	// - prec: 小数点后保留几位小数
	// - bitSize: must be 64 for complex64 and 128 for complex128, 否则panic, 若转换为32位的, 则可能精度损失
	str = strconv.FormatComplex(num3, 'f', 10, 64)  // (3.1415927410+3.1415927410i)
	str = strconv.FormatComplex(num3, 'f', 10, 128) // (3.1415926536+3.1415926536i)
	fmt.Println(str)
}

// 切片转换成字符串
// 只有这三种类型的切片才可以转换成字符串: []byte、[]rune、[]int32
func SliceToString() {
	// • string([]byte)
	byteSlice := make([]byte, 5)
	for i := 0; i < 5; i++ {
		byteSlice[i] = byte(i + 65)
	}
	fmt.Println(byteSlice)         // [65 66 67 68 69]
	fmt.Println(string(byteSlice)) // ABCDE

	// • string([]rune)
	runeSlice := make([]rune, 5)
	for i := 0; i < 5; i++ {
		runeSlice[i] = rune(i + 97)
	}
	fmt.Println(runeSlice)         // [97 98 99 100 101]
	fmt.Println(string(runeSlice)) // abcde

	// • string([]int32)
	int32Slice := make([]int32, 5)
	for i := 0; i < 5; i++ {
		int32Slice[i] = int32(i + 97)
	}
	fmt.Println(int32Slice)         // [97 98 99 100 101]
	fmt.Println(string(int32Slice)) // abcde
}

// 字符串转换成有符号整数类型
func StringToIntStrconv() {
	var err error
	var j int64
	// • Atoi(s string) (int, error)
	// Atoi is equivalent to ParseInt(s, 10, 0)
	i, _ := strconv.Atoi("100")
	fmt.Println(i)
	// • ParseInt(s string, base int, bitSize int) (i int64, err error)
	// 参数说明:
	// - base: 代表输入字符串是哪一种进制, 它的范围是[0, 36]的闭区间并且base不能等于1, 不在区间内则返回0, error
	// base=0, 函数会根据字符串的前缀来判断, 0b代表二进制、0o代表八进制、0x代表十六进制, 其余都是按十进制处理
	j, err = strconv.ParseInt("0b101", 0, 64) // 5 <nil>
	j, err = strconv.ParseInt("0o101", 0, 64) // 65 <nil>
	j, err = strconv.ParseInt("101", 0, 64)   // 101 <nil>
	j, err = strconv.ParseInt("0x101", 0, 64) // 257 <nil>
	// base=2, 代表输入的字符串是二进制形式, 不需要加前缀0b, 若字符串不符合二进制形式, 则返回0, error
	j, err = strconv.ParseInt("101", 2, 64) // 5 <nil>
	j, err = strconv.ParseInt("102", 2, 64) // 0 strconv.ParseInt: parsing "102": invalid syntax
	// base=8, 代表输入的字符串是八进制形式, 不需要加前缀0o, 若字符串不符合八进制形式, 则返回0, error
	j, err = strconv.ParseInt("20", 8, 64) // 16 <nil>
	j, err = strconv.ParseInt("80", 8, 64) // 0 strconv.ParseInt: parsing "80": invalid syntax
	// base=16, 代表输入的字符串是十六进制形式, 不需要加前缀0x, 若字符串不符合十六进制形式, 则返回0, error
	j, err = strconv.ParseInt("a0", 16, 64) // 160 <nil>
	j, err = strconv.ParseInt("z0", 16, 64) // 0 strconv.ParseInt: parsing "z0": invalid syntax
	// base=n, 代表输入的字符串是n进制形式, 不需要加前缀, 字符串中的每一个字符必须小于n, 否则返回0, error
	j, err = strconv.ParseInt("a0", 30, 64) // 300 <nil>  300=10*30^1
	j, err = strconv.ParseInt("30", 3, 64)  // 0 strconv.ParseInt: parsing "30": invalid syntax
	// base=(-inf, 0) U 1 U [37, +inf)
	j, err = strconv.ParseInt("101", 1, 64) // 0 strconv.ParseInt: parsing "101": invalid base 1
	// - bitSize: 转换后的数据必须在bitSize这个类型支持的范围内, 它的范围是[0, 64]的闭区间, 不在区间内则返回0, error
	// bitSize=0对应int, 因此字符串s按照base转换后的值必须在int支持的范围内
	// bitSize=8对应int8, 因此字符串s按照base转换后的值必须在int8支持的范围内
	// bitSize=16对应int16, 因此字符串s按照base转换后的值必须在int16支持的范围内
	// bitSize=32对应int32, 因此字符串s按照base转换后的值必须在int32支持的范围内
	// bitSize=64对应int64, 因此字符串s按照base转换后的值必须在int64支持的范围内
	// 当bitSize等于其他数值时, 返回值的取值范围计算公式: [-2^(bitSize-1), 2^(bitSize-1)-1], 如bitSize=5, 范围为[-16, 15]
	j, err = strconv.ParseInt("-1", 10, 5) // -1 nil
	// 若字符串为负数形式, 且小于取值范围的最小值, 则返回取值范围的最小值
	// 若字符串为正数形式, 且大于取值范围的最大值, 则返回取值范围的最大值
	j, err = strconv.ParseInt("1000", 10, 5) // 15 strconv.ParseInt: parsing "1000": value out of range
	j, err = strconv.ParseInt("-17", 10, 5)  // -16 strconv.ParseInt: parsing "-17": value out of range
	// 输入字符串不符合base
	j, err = strconv.ParseInt("AB", 10, 5) // 0 strconv.ParseInt: parsing "AB": invalid syntax
	fmt.Println(j, err)
}

// 字符串转换成无符号整数类型
func StringToUintStrconv() {
	var i uint64
	var err error
	// • ParseUint(s string, base int, bitSize int) (uint64, error)
	// 使用方法同ParseInt
	// 若输入字符串为非数字形式、负数、不符合base进制的表达, 均返回0 error
	i, err = strconv.ParseUint("X", 0, 64)    // 0 strconv.ParseInt: parsing "AB": invalid syntax
	i, err = strconv.ParseUint("-101", 0, 64) // 0 strconv.ParseUint: parsing "-101": invalid syntax
	i, err = strconv.ParseUint("999", 2, 64)  // 0 strconv.ParseUint: parsing "999": invalid syntax
	fmt.Println(i, err)
}

// 字符串转换成浮点数类型
func StringToFloatStrconv() {
	var f float64
	var err error
	// • ParseFloat(s string, bitSize int) (float64, error)
	// 参数说明:
	// - bitSize: 32、64, 代表精度, 使用32可能造成损失, 若bitSize不等于32或者64, 统一按照64计算
	f, err = strconv.ParseFloat("1.23456789098765", 32)     // 1.2345678806304932 <nil>
	f, err = strconv.ParseFloat("1.23456789098765", 64)     // 1.23456789098765 <nil>
	f, err = strconv.ParseFloat("1.23456789098765", 100000) // 1.23456789098765 <nil>
	// 特殊字符串Inf、Infinity、NaN
	f, err = strconv.ParseFloat("Inf", 64)      // +Inf <nil>
	f, err = strconv.ParseFloat("Infinity", 64) // +Inf <nil>
	f, err = strconv.ParseFloat("NaN", 64)      // NaN <nil>
	fmt.Println(f, err)
}

// 字符串转换成布尔类型
func StringToBoolStrconv() {
	var b bool
	var err error
	// • ParseBool(str string) (bool, error)
	// 参数说明:
	// str只接收: 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
	b, err = strconv.ParseBool("1")     // true <nil>
	b, err = strconv.ParseBool("t")     // true <nil>
	b, err = strconv.ParseBool("TRUE")  // true <nil>
	b, err = strconv.ParseBool("true")  // true <nil>
	b, err = strconv.ParseBool("True")  // true <nil>
	b, err = strconv.ParseBool("0")     // false <nil>
	b, err = strconv.ParseBool("f")     // false <nil>
	b, err = strconv.ParseBool("F")     // false <nil>
	b, err = strconv.ParseBool("FALSE") // false <nil>
	b, err = strconv.ParseBool("false") // false <nil>
	b, err = strconv.ParseBool("False") // false <nil>
	// 非布类类型字符串返回false error
	b, err = strconv.ParseBool("100") // false strconv.ParseBool: parsing "100": invalid syntax
	fmt.Println(b, err)
}

func main() {
	BaseToBase()
	BaseToStringSprintf()
	BaseToStringStrconv()
	SliceToString()
	StringToIntStrconv()
	StringToUintStrconv()
	StringToFloatStrconv()
	StringToBoolStrconv()
}
